package com.siemens.industrial.web.mvc.service.partner;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.siemens.industrial.model.partner.Device;
import com.siemens.industrial.utils.ConfigurationUtil;
import com.siemens.industrial.utils.GlobalResponseCode;
import com.siemens.industrial.utils.SiemensException;
import com.siemens.industrial.utils.UUIDGenerator;
import com.siemens.industrial.web.mvc.dao.admin.DeviceDao;
import com.siemens.industrial.web.mvc.dao.partner.PartnerDeviceDao;
import com.siemens.industrial.web.mvc.pojo.DataTableQuery;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;

/**
 * Created by qupen on 2016/8/31.
 */
@Service
public class PartnerDeviceService {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Resource
    PartnerDeviceDao partnerDeviceDao;

    @Resource
    DeviceDao deviceDao;

    @Resource
    JdbcTemplate jdbcTemplate;

    public Device getDevice(String tenantId, String deviceId) {
        return partnerDeviceDao.getDevice(tenantId, deviceId);
    }

    public List<Map<String, Object>> getDevices(String tenantId) {
        return partnerDeviceDao.getDevices(tenantId);
    }

    @Transactional
    public void saveDevice(String tenantId, Map<String, Object> data, String deviceId) throws URISyntaxException {
        com.siemens.industrial.model.admin.Device userDevice = new com.siemens.industrial.model.admin.Device();
        Device device = new Device();
        device.setDeviceId(deviceId);
        device.setLine(data.get("line").toString());
        device.setDeviceType(data.get("type").toString());
        device.setDeviceUniqueId(data.get("uniqueId").toString());
        device.setDeviceManufactory(data.get("manufactory").toString());
        device.setGroup(data.get("group").toString());
        device.setDeviceName(data.get("name").toString());
        device.setPurchaseDate(data.get("purchaseDate").toString());
        device.setDeviceModel(data.get("model").toString());
        device.setDeviceImg(data.get("image").toString());
        device.setDescription(data.get("description").toString());

        userDevice.setDeviceId(deviceId);
        userDevice.setDeviceUniqueId(data.get("uniqueId").toString());
        userDevice.setTenantId(tenantId);
        userDevice.setModel(data.get("model").toString());
        userDevice.setType(data.get("type").toString());
        userDevice.setGroup(data.get("group").toString());
        userDevice.setLine(data.get("line").toString());
        userDevice.setPurchaseDate(data.get("purchaseDate").toString());
        userDevice.setDeviceName(data.get("name").toString());
        userDevice.setManufacturer(data.get("manufactory").toString());
        userDevice.setServiceAddress(data.get("description").toString());
        userDevice.setDeviceImg(data.get("image").toString());
        partnerDeviceDao.saveDevice(tenantId, device);
        deviceDao.save(userDevice);
    }

    @Transactional
    public void updateDevice(String tenantId, Map<String, Object> data) throws SiemensException {
        Device device = partnerDeviceDao.getDevice(tenantId, data.get("deviceId").toString());
        com.siemens.industrial.model.admin.Device userDevice = deviceDao.findOneById(data.get("deviceId").toString());
        if (device != null && userDevice != null) {
            device.setDeviceType(data.get("type").toString());
            device.setDeviceModel(data.get("model").toString());
            device.setDescription(data.get("description").toString());
//            device.setServiceAddress(data.get("address").toString());
            device.setLine(data.get("line").toString());
            device.setDeviceManufactory(data.get("manufactory").toString());
            device.setDeviceName(data.get("name").toString());
            device.setGroup(data.get("group").toString());
            device.setDeviceImg(data.get("image").toString());
            device.setPurchaseDate(data.get("purchaseDate").toString());
            partnerDeviceDao.updateDevice(tenantId, device);

            userDevice.setType(data.get("type").toString());
            userDevice.setModel(data.get("model").toString());
            userDevice.setDescription(data.get("description").toString());
//            device.setServiceAddress(data.get("address").toString());
            userDevice.setLine(data.get("line").toString());
            userDevice.setManufacturer(data.get("manufactory").toString());
            userDevice.setDeviceName(data.get("name").toString());
            userDevice.setGroup(data.get("group").toString());
            userDevice.setDeviceImg(data.get("image").toString());
            userDevice.setPurchaseDate(data.get("purchaseDate").toString());
            deviceDao.update(userDevice);

        } else {
            throw new SiemensException(GlobalResponseCode.ERROR_DEVICE_NOT_EXISTED);
        }
    }

    @Transactional
    public void deleteDevice(String tenantId, String deviceId) throws SiemensException {
        Device device = partnerDeviceDao.getDevice(tenantId, deviceId);
        if (device != null) {
            partnerDeviceDao.deleteDevice(tenantId, deviceId);
            deviceDao.updateById(deviceId);
        } else {
            throw new SiemensException(GlobalResponseCode.ERROR_DEVICE_NOT_EXISTED);
        }
    }

    public Device getDeviceById(String tenantId, String deviceId) {
        return partnerDeviceDao.getDeviceByDeviceId(tenantId, deviceId);
    }

    public List<Device> getDeviceList(String tenantId) {
        return partnerDeviceDao.getDeviceList(tenantId);
    }

    public List<Device> getAll(String tenantId) {
        return partnerDeviceDao.findAll(tenantId);
    }

    public Device getDeviceByUniqueId(String tenantId, String uniqueId) {
        return partnerDeviceDao.getDeviceByUniqueId(tenantId, uniqueId);
    }

    public List<String> getDeviceType(String database) {
        return partnerDeviceDao.getDeviceType(database);
    }

    public List<Map<String, Object>> getDeviceAndState(String database, String deviceId) {
        return partnerDeviceDao.findDeviceAndState(database, deviceId);
    }

    public Map<String, Object> getChartForHeader(String tenantId) {
        List<Map<String, Object>> models = partnerDeviceDao.findAllDistinctDeviceModel(tenantId);
        List<Map<String, Object>> types = partnerDeviceDao.findAllDistinctDeviceType(tenantId);
        List<Map<String, Object>> groups = partnerDeviceDao.findAllDistinctDeviceGroup(tenantId);
        List<Map<String, Object>> lines = partnerDeviceDao.findAllDistinctDeviceLine(tenantId);

        return new HashMap<String, Object>() {{
            put("models", models);
            put("types", types);
            put("groups", groups);
            put("lines", lines);
        }};
    }

    public List<Map<String, Object>> getAllMtInfo(String tenantId, String model, String type, String group, String line) {
        String sql = "select * from `" + tenantId + "`.device where delete_time is null";
        if (!model.equals("")) {
            sql += " and `device_model` ='" + model + "'";
        }
        if (!type.equals("")) {
            sql += " and `device_type` ='" + type + "'";
        }
        if (!group.equals("")) {
            sql += " and `group` ='" + group + "'";
        }
        if (!line.equals("")) {
            sql += " and `line` ='" + line + "'";
        }
        sql += " order by `device_unique_id` asc";
        return partnerDeviceDao.getListBySearch(sql);
    }

    public Map<String, Object> getLinesAndGroupsMtInfo(String tenantId, String model, String type) {
        List<Map<String, Object>> lines = partnerDeviceDao.getLinesByTypeAndMode(tenantId, type, model);
        List<Map<String, Object>> groups = partnerDeviceDao.getGroupsByTypeAndMode(tenantId, type, model);

        return new HashMap<String, Object>() {{
            put("lines", lines);
            put("groups", groups);
        }};
    }

    @Transactional
    public void adadadasd(String tenantId) {
        List<Device> list = partnerDeviceDao.findAll(tenantId);
        for (Device device : list) {
            com.siemens.industrial.model.admin.Device device1 = new com.siemens.industrial.model.admin.Device();
            device1.setDeviceId(device.getDeviceId());
            device1.setDeviceUniqueId(device.getDeviceUniqueId());
            device1.setTenantId(tenantId);
            device1.setModel(device.getDeviceModel());
            device1.setType(device.getDeviceType());
            device1.setGroup(device.getGroup());
            device1.setLine(device.getLine());
            device1.setPurchaseDate(device.getPurchaseDate());
            device1.setDeviceName(device.getDeviceName());
            device1.setServiceAddress(device.getServiceAddress());
            device1.setLastHeartBeat(device.getLastHeartbeatTime());
            device1.setManufacturer(device.getDeviceManufactory());
            device1.setDescription(device.getDescription());
            device1.setDeviceImg(device.getDeviceImg());
            device1.setDeleteTime(device.getDeleteTime());

            deviceDao.save(device1);
        }
    }

    public List<Map<String, Object>> getAllMTIdsLike(String tenantId, String str) {
        return partnerDeviceDao.findAllLikeMtId(tenantId, str);
    }

    public List<Map<String, Object>> getAllIdleLike(String tenantId, String str) {
        return partnerDeviceDao.findAllLikeIdle(tenantId, str);
    }

    //dataTable search devices
    public Map<String, Object> getDevicesByDataTable(String tenantId, HttpServletRequest request) {
        DataTableQuery dt = new DataTableQuery(request);
        List<Map<String, Object>> list = new ArrayList<>();

        String sql = "SELECT \n" +
                "    a.device_id,\n" +
                "    a.device_unique_id,\n" +
                "    a.device_model,\n" +
                "    a.device_type,\n" +
                "    a.description,\n" +
                "    c.state\n" +
                "FROM\n" +
                "    `" + tenantId + "`.device a\n" +
                "        LEFT JOIN\n" +
                "    (SELECT * FROM\n" +
                "        (SELECT \n" +
                "        CASE\n" +
                "                WHEN @d_id != device_id THEN @rownum:=1\n" +
                "                ELSE @rownum:=@rownum + 1\n" +
                "            END AS rownum,\n" +
                "            @d_id:=device_id AS device_id,\n" +
                "            d.time,\n" +
                "            d.state,\n" +
                "            d.source_ip,\n" +
                "            d.write_time\n" +
                "    FROM\n" +
                "        (SELECT @d_id:='') k, (SELECT @rownum:=0) r, `" + tenantId + "`.device_state d\n" +
                "    WHERE\n" +
                "        d.time >= DATE_ADD(NOW(), INTERVAL 1 MINUTE)\n" +
                "    ORDER BY device_id , time DESC) a\n" +
                "    WHERE\n" +
                "        rownum = 1) c ON a.device_id = c.device_id\n" +
                "WHERE\n" +
                "    a.delete_time IS NULL\n";
        int total = jdbcTemplate.queryForList(sql).size();
        int filteredCount = total;
        if (!dt.getSearch().equals("")) {
            String search = " and(a.device_id like '%" + dt.getSearch() + "%' or a.device_unique_id like '%" + dt.getSearch() + "%' or a.device_model like '%" + dt.getSearch() + "%' or a.device_type like '%" + dt.getSearch() + "%' or a.description like '%" + dt.getSearch() + "%' or c.state like '%" + dt.getSearch() + "%')";
            sql += search;
            filteredCount = jdbcTemplate.queryForList(sql + search).size();
        }

        if (!dt.getOrderDBColumn().equals("") && !dt.getOrderAscOrDesc().equals("")) {
            String order = " ORDER BY `" + dt.getOrderDBColumn() + "` " + dt.getOrderAscOrDesc();
            sql += order;
        } else {
            String order = " ORDER BY `a.device_unique_id`";
            sql += order;
        }

        String limit = " limit " + dt.getStart() + "," + dt.getLength();
        sql += limit;

        list = jdbcTemplate.queryForList(sql);
        return dt.buildResponse(filteredCount, total, list);
    }

    public void updateStatus(String tenantId, Map<String, Object> map) {
        int status = Integer.parseInt(map.get("status").toString());
        String eventId = map.get("eventId").toString();
        String mtid = map.get("mtid").toString();
        long stateTime = Long.parseLong(map.get("startTime").toString());

        partnerDeviceDao.updateMessageStatus(tenantId, status, eventId, mtid, new Date(stateTime));
    }

    public List<Map<String, Object>> getAllMTNamesLike(String tenantId, String str) {
        return partnerDeviceDao.findAllLikeName(tenantId, str);
    }

    public List<Map<String, Object>> getAllMTTypesLike(String tenantId, String str) {
        return partnerDeviceDao.findAllLikeMtType(tenantId, str);
    }

    public List<Map<String, Object>> getAllMTModelsLike(String tenantId, String str) {
        return partnerDeviceDao.findAllLikeModel(tenantId, str);
    }

    public List<Map<String, Object>> getAllMTGroupsLike(String tenantId, String str) {
        return partnerDeviceDao.findAllLikeGroup(tenantId, str);
    }

    public List<Map<String, Object>> getAllMTLinesLike(String tenantId, String str) {
        return partnerDeviceDao.findAllLikeLine(tenantId, str);
    }

    public List<Map<String, Object>> getAllMTMadesLike(String tenantId, String str) {
        return partnerDeviceDao.findAllLikeMade(tenantId, str);
    }

    public List<Map<String, Object>> getAllDistinctGroups(String tenantId) {
        return partnerDeviceDao.findDistinctAllGroups(tenantId);
    }

    public List<Map<String, Object>> getAllDistinctLines(String tenantId) {
        return partnerDeviceDao.findDistinctAllLines(tenantId);
    }

    public List<Device> getAllDeviceSearchInfo(String tenantId, String mtid, String type, String model, String name, String group, String line, String made) {
        String sql = "select * from `" + tenantId + "`.device where 1=1";
        StringBuffer sb = new StringBuffer(sql);
        if (!mtid.equals("")) {
            sb.append(" and `device_unique_id` = '" + mtid + "'");
        }
        if (!type.equals("")) {
            sb.append(" and `device_type` = '" + type + "'");
        }
        if (!model.equals("")) {
            sb.append(" and `device_model` = '" + model + "'");
        }
        if (!name.equals("")) {
            sb.append(" and `device_name` = '" + name + "'");
        }
        if (!group.equals("")) {
            sb.append(" and `group` = '" + group + "'");
        }
        if (!line.equals("")) {
            sb.append(" and `line` = '" + line + "'");
        }
        if (!made.equals("")) {
            sb.append(" and `device_manufactory` = '" + made + "'");
        }

        String finallySql = sb.toString();
        return partnerDeviceDao.getDeviceForSearch(finallySql);
    }


    public Map<String, Object> getDeviceSearchByDateTable(String tenantId, String mtid, String type, String model, String name, String group, String line, String made, HttpServletRequest request) {
        DataTableQuery dt = new DataTableQuery(request);
        String sql = "select * from `" + tenantId + "`.device where 1=1";
        int total = jdbcTemplate.queryForList(sql).size();

        StringBuffer sb = new StringBuffer(sql);
        if (!mtid.equals("")) {
            sb.append(" and `device_unique_id` = '" + mtid + "'");
        }
        if (!type.equals("")) {
            sb.append(" and `device_type` = '" + type + "'");
        }
        if (!model.equals("")) {
            sb.append(" and `device_model` = '" + model + "'");
        }
        if (!name.equals("")) {
            sb.append(" and `device_name` = '" + name + "'");
        }
        if (!group.equals("")) {
            sb.append(" and `group` = '" + group + "'");
        }
        if (!line.equals("")) {
            sb.append(" and `line` = '" + line + "'");
        }
        if (!made.equals("")) {
            sb.append(" and `device_manufactory` = '" + made + "'");
        }

        if (!dt.getOrderDBColumn().equals("") && !dt.getOrderAscOrDesc().equals("")) {
            sb.append(" ORDER BY `" + dt.getOrderDBColumn() + "` " + dt.getOrderAscOrDesc());
        } else {
            sb.append(" ORDER BY `a.device_unique_id`");
        }

        sb.append(" limit " + dt.getStart() + "," + dt.getLength());

        String finallySql = sb.toString();
        List<Map<String, Object>> list = jdbcTemplate.queryForList(finallySql);
        return dt.buildResponse(list.size(), total, list);
    }

    public String startExportXml(String tenantId) throws IOException {
        List<Device> list = getDeviceList(tenantId);
        // 创建根节点 并设置它的属性 ;
        Element root = new Element("Devices").setAttribute("count", String.valueOf(list.size()));
        // 将根节点添加到文档中；
        Document Doc = new Document(root);
        for (Device device : list) {
            Element elements = new Element("Device");
            // 给 book 节点添加子节点并赋值；
            elements.addContent(new Element("device_id").setText(device.getDeviceId()));
            elements.addContent(new Element("device_unique_id").setText(device.getDeviceUniqueId()));
            elements.addContent(new Element("device_model").setText(device.getDeviceModel()));
            elements.addContent(new Element("device_type").setText(device.getDeviceType()));
            elements.addContent(new Element("group").setText(device.getGroup()));
            elements.addContent(new Element("line").setText(device.getLine()));
            elements.addContent(new Element("purchase_date").setText(device.getPurchaseDate()));
            elements.addContent(new Element("device_name").setText(device.getDeviceName()));
            elements.addContent(new Element("device_manufactory").setText(device.getDeviceManufactory()));
            elements.addContent(new Element("description").setText(device.getDescription()));
            elements.addContent(new Element("device_img").setText(device.getDeviceImg()));
            elements.addContent(new Element("create_time").setText(String.valueOf(device.getCreateTime().getTime())));

            root.addContent(elements);
        }
        Format format = Format.getPrettyFormat();
        XMLOutputter XMLOut = new XMLOutputter(format);
        String path = ConfigurationUtil.INSTANCE.getDeviceXmlPath();
        String fileName = UUIDGenerator.getUUID();
        File file = new File(path + fileName);
        if (!file.exists()) {
            file.createNewFile();
        }
        FileOutputStream out = new FileOutputStream(file);
        XMLOut.output(Doc, out);
        out.close();
        return fileName;
    }
}
